// Taken from: https://github.com/skyrpex/RichText
#ifndef UTIL3DS_RICHTEXT_HPP
#define UTIL3DS_RICHTEXT_HPP

//////////////////////////////////////////////////////////////////////////
// Headers
//////////////////////////////////////////////////////////////////////////
#include <vector>

#include <cpp3ds/Graphics/Drawable.hpp>
#include <cpp3ds/Graphics/Color.hpp>
#include <cpp3ds/Graphics/Text.hpp>
#include <cpp3ds/System/Vector2.hpp>
#include "TweenObjects.hpp"

namespace util3ds
{

class RichText : public cpp3ds::Drawable, public TweenTransformable<cpp3ds::Transformable>
{
public:
    //////////////////////////////////////////////////////////////////////////
    // Nested class that represents a single line
    //////////////////////////////////////////////////////////////////////////
    class Line : public cpp3ds::Transformable, public cpp3ds::Drawable
    {
    public:
        //////////////////////////////////////////////////////////////////////
        // Set character size
        //////////////////////////////////////////////////////////////////////
        void setCharacterSize(unsigned int size);

        //////////////////////////////////////////////////////////////////////
        // Set font
        //////////////////////////////////////////////////////////////////////
        void setFont(const cpp3ds::Font &font);

        //////////////////////////////////////////////////////////////////////
        // Get texts
        //////////////////////////////////////////////////////////////////////
        std::vector<cpp3ds::Text> &getTexts() const;

        //////////////////////////////////////////////////////////////////////
        // Append text
        //////////////////////////////////////////////////////////////////////
        void appendText(cpp3ds::Text text);

        //////////////////////////////////////////////////////////////////////
        // Get local bounds
        //////////////////////////////////////////////////////////////////////
        cpp3ds::FloatRect getLocalBounds() const;

        //////////////////////////////////////////////////////////////////////
        // Get global bounds
        //////////////////////////////////////////////////////////////////////
        cpp3ds::FloatRect getGlobalBounds() const;

		void setOpacity(cpp3ds::Uint8 alpha);
		cpp3ds::Uint8 getOpacity() const;

    protected:
        //////////////////////////////////////////////////////////////////////
        // Draw
        //////////////////////////////////////////////////////////////////////
        void draw(cpp3ds::RenderTarget &target, cpp3ds::RenderStates states) const override;

    private:
        //////////////////////////////////////////////////////////////////////
        // Update geometry
        //////////////////////////////////////////////////////////////////////
        void updateGeometry() const;

        //////////////////////////////////////////////////////////////////////
        // Update geometry for a given text
        //////////////////////////////////////////////////////////////////////
        void updateTextAndGeometry(cpp3ds::Text &text) const;

        //////////////////////////////////////////////////////////////////////
        // Member data
        //////////////////////////////////////////////////////////////////////
        mutable std::vector<cpp3ds::Text> m_texts; ///< List of texts
        mutable cpp3ds::FloatRect m_bounds;        ///< Local bounds
    };

    //////////////////////////////////////////////////////////////////////////
    // Constructor
    //////////////////////////////////////////////////////////////////////////
    RichText();

    //////////////////////////////////////////////////////////////////////////
    // Constructor
    //////////////////////////////////////////////////////////////////////////
    RichText(const cpp3ds::Font &font);

    //////////////////////////////////////////////////////////////////////////
    // Operators
    //////////////////////////////////////////////////////////////////////////
    RichText & operator << (const cpp3ds::Color &color);
    RichText & operator << (cpp3ds::Text::Style style);
    RichText & operator << (const cpp3ds::String &string);

    //////////////////////////////////////////////////////////////////////////
    // Set character size
    //////////////////////////////////////////////////////////////////////////
    void setCharacterSize(unsigned int size);

    //////////////////////////////////////////////////////////////////////////
    // Set font
    //////////////////////////////////////////////////////////////////////////
    void setFont(const cpp3ds::Font &font);

	void setOpacity(cpp3ds::Uint8 alpha);
	cpp3ds::Uint8 getOpacity() const;

    void useSystemFont();

    //////////////////////////////////////////////////////////////////////////
    // Clear
    //////////////////////////////////////////////////////////////////////////
    void clear();

    //////////////////////////////////////////////////////////////////////////
    // Get text list
    //////////////////////////////////////////////////////////////////////////
    const std::vector<Line> &getLines() const;

    //////////////////////////////////////////////////////////////////////////
    // Get character size
    //////////////////////////////////////////////////////////////////////////
    unsigned int getCharacterSize() const;

    //////////////////////////////////////////////////////////////////////////
    // Get font
    //////////////////////////////////////////////////////////////////////////
    const cpp3ds::Font *getFont() const;

    //////////////////////////////////////////////////////////////////////////
    // Get local bounds
    //////////////////////////////////////////////////////////////////////////
    cpp3ds::FloatRect getLocalBounds() const;

    //////////////////////////////////////////////////////////////////////////
    // Get global bounds
    //////////////////////////////////////////////////////////////////////////
    cpp3ds::FloatRect getGlobalBounds() const;

protected:
    //////////////////////////////////////////////////////////////////////////
    // Render
    //////////////////////////////////////////////////////////////////////////
    void draw(cpp3ds::RenderTarget &target, cpp3ds::RenderStates states) const override;

private:
    //////////////////////////////////////////////////////////////////////////
    // Delegate constructor
    //////////////////////////////////////////////////////////////////////////
    RichText(const cpp3ds::Font *font);

    //////////////////////////////////////////////////////////////////////////
    // Creates a cpp3ds::Text instance using the current styles
    //////////////////////////////////////////////////////////////////////////
    cpp3ds::Text createText(const cpp3ds::String &string) const;

    //////////////////////////////////////////////////////////////////////////
    // Update geometry
    //////////////////////////////////////////////////////////////////////////
    void updateGeometry() const;

    //////////////////////////////////////////////////////////////////////////
    // Member data
    //////////////////////////////////////////////////////////////////////////
    mutable std::vector<Line> m_lines;  ///< List of lines
    const cpp3ds::Font *m_font;         ///< Font
    unsigned int m_characterSize;       ///< Character size
    mutable cpp3ds::FloatRect m_bounds; ///< Local bounds
    cpp3ds::Color m_currentColor;       ///< Last used color
    cpp3ds::Text::Style m_currentStyle; ///< Last style used
    bool m_useSystemFont;
};

} // namespace util3ds

#endif // UTIL3DS_RICHTEXT_HPP
